package com.siyoumi.app.modules.iot.service;

import com.siyoumi.app.entity.IotDevice;
import com.siyoumi.app.entity.IotDeviceLog;
import com.siyoumi.app.modules.iot.vo.VaIotDevice;
import com.siyoumi.app.netty.NettyMqttUtil;
import com.siyoumi.app.service.IotDeviceLogService;
import com.siyoumi.app.service.IotDeviceService;
import com.siyoumi.component.XApp;
import com.siyoumi.component.XRedis;
import com.siyoumi.component.XSpringContext;
import com.siyoumi.component.http.InputData;
import com.siyoumi.component.http.XHttpContext;
import com.siyoumi.exception.EnumSys;
import com.siyoumi.mybatispuls.JoinWrapperPlus;
import com.siyoumi.service.IWebService;
import com.siyoumi.util.XDate;
import com.siyoumi.util.XReturn;
import com.siyoumi.util.XStr;
import io.netty.channel.Channel;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

//设备
@Slf4j
@Service
public class SvcIotDevice
        implements IWebService {
    static public SvcIotDevice getBean() {
        return XSpringContext.getBean(SvcIotDevice.class);
    }

    static public IotDeviceService getApp() {
        return IotDeviceService.getBean();
    }

    public JoinWrapperPlus<IotDevice> listQuery() {
        return listQuery(InputData.getIns());
    }

    public String getTopic() {
        return "siyoumi";
    }


    /**
     * 设备状态
     * 1:在线；0:离线；
     *
     * @param entityDev
     */
    public Integer getState(IotDevice entityDev) {
        Channel channel = NettyMqttUtil.getMapChannel().get(getMqttQueueId(entityDev));
        if (channel != null) {
            return 1;
        }
        return 0;
    }

    public String getMqttQueueId(IotDevice entityDev) {
        return getMqttQueueId(entityDev.getIdev_pro_id(), entityDev.getIdev_num());
    }

    /**
     * mqtt队列ID
     *
     * @param productId
     * @param deviceNum
     */
    public String getMqttQueueId(String productId, String deviceNum) {
        return XStr.concat(productId, ".", deviceNum);
    }


    public IotDevice getEntity(String queueId) {
        String[] queueData = queueId.split("\\.");
        return getEntity(queueData[0], queueData[1]);
    }

    /**
     * 根据设备号，获取设备
     *
     * @param deviceNum
     */
    public IotDevice getEntity(String productId, String deviceNum) {
        String key = getApp().getEntityCacheKey(getMqttQueueId(productId, deviceNum), false);
        return XRedis.getBean().getAndSetData(key, k -> {
            JoinWrapperPlus<IotDevice> query = getApp().join();
            query.eq("idev_pro_id", productId)
                    .eq("idev_num", deviceNum);
            return getApp().first(query);
        }, IotDevice.class);
    }

    public XReturn checkDevice(IotDevice entityDev) {
        if (entityDev == null) {
            return EnumSys.ERR_VAL.getR("设备ID异常");
        }
        if (entityDev.getIdev_del() != 0) {
            return XReturn.getR(50052, "设备已删除");
        }

        return EnumSys.OK.getR();
    }

    /**
     * 检查参数
     * ${rndStr};${expTimestamp};{sign}
     *
     * @param entityDev
     * @param pwd
     */
    public XReturn checkPwd(IotDevice entityDev, String pwd) {
        if (entityDev.getIdev_del() != 0) {
            return XReturn.getR(50052, "设备已删除");
        }

        String[] pwdArr = pwd.split(";");
        if (pwdArr.length != 3) {
            return XReturn.getR(50055, "密码错误");
        }

        String rndStr = pwdArr[0]; //随机字符串
        String expTimestamp = pwdArr[1]; //表示签名的有效期
        String sign = pwdArr[2];
        LocalDateTime expDate = XDate.parseTimestamp(expTimestamp);
        Duration between = XDate.between(LocalDateTime.now(), expDate);
        log.debug("sign minutes: {}", between.toMinutes());
        if (Math.abs(between.toMinutes()) > 5) {
            //超5分钟
            return XReturn.getR(50058, "密码已失效");
        }

        String sysSign = sign(getMqttQueueId(entityDev), rndStr, expTimestamp, entityDev.getIdev_key());
        if (sign.equals(sysSign)) {
            return XReturn.getR(0);
        }

        return XReturn.getR(50062, "设备签名失败");
    }

    public String sign(String username, String rndStr, String timestamp, String key) {
        String string1 = username + rndStr + timestamp + key;
        String sign = XStr.sha256(string1);

        log.info("string1: {}", string1);
        log.info("sign: {}", sign);
        return sign;
    }

    /**
     * 记录日志
     *
     * @param queueId
     * @param type
     * @param content
     * @return
     */
    public IotDeviceLog addLog(String queueId, String type, String content) {
        IotDevice entityDev = getEntity(queueId);
        IotDeviceLog entity = new IotDeviceLog();
        entity.setIdlog_x_id(entityDev.getIdev_x_id());
        entity.setIdlog_pro_id(entityDev.getIdev_pro_id());
        entity.setIdlog_device_id(entityDev.getIdev_id());
        entity.setIdlog_type(type);
        entity.setIdlog_content(content);
        entity.setAutoID();

        IotDeviceLogService.getBean().save(entity);
        return entity;
    }

    /**
     * select
     *
     * @return query
     */
    public JoinWrapperPlus<IotDevice> listQuery(InputData inputData) {
        String num = inputData.input("num");

        JoinWrapperPlus<IotDevice> query = getApp().join();
        query.eq("idev_x_id", XHttpContext.getX())
                .eq("idev_del", 0);
        getApp().addQueryAcc(query);

        if (XStr.hasAnyText(num)) { //设备号
            query.eq("idev_num", num);
        }

        return query;
    }

    public JoinWrapperPlus<IotDeviceLog> listLogQuery(InputData inputData) {
        String deviceId = inputData.input("device_id");

        JoinWrapperPlus<IotDeviceLog> query = IotDeviceLogService.getBean().join();
        query.eq("idlog_x_id", XHttpContext.getX())
        ;

        if (XStr.hasAnyText(deviceId)) { //设备号
            query.eq("idlog_device_id", deviceId);
        }

        return query;
    }

    public XReturn edit(InputData inputData, VaIotDevice vo) {
        List<String> ignoreField = new ArrayList<>();
        if (inputData.isAdminEdit()) {
            ignoreField.add(getApp().fdAccId());
            vo.setIdev_key(null);
        } else {
            vo.setIdev_key(XApp.getUUID());
        }

        return XApp.getTransaction().execute(status -> {
            XReturn r = getApp().saveEntity(inputData, vo, true, ignoreField);

            return r;
        });
    }

    /**
     * 删除
     */
    @SneakyThrows
    @Transactional(propagation = Propagation.MANDATORY)
    public XReturn delete(List<String> ids) {
        XReturn r = XReturn.getR(0);
        getApp().delete(ids);

        return r;
    }
}
